2.5 引用类型

所谓引用类型(reference type)特指slice、map、channel这三种预定义类型

相比数字、数组等类型,引用类型拥有更复杂的存储结构。除分配内存外,它们还须初始化一系列属性,诸如指针、长度,甚至包括哈希分布、数据队列等

内置函数new按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。而引用类型则必须使用make函数创建,编译器会将make转换为目标类型专用的创建函数(或指令),以确保完成全部内存分配和相关属性初始化

func mkslice() []int{ 
   s:=make([]int,0,10) 
   s=append(s,100) 
   return s
} 
  
func mkmap()map[string]int{ 
   m:=make(map[string]int) 
   m["a"] =1
   return m
} 
  
func main() { 
   m:=mkmap() 
   println(m["a"]) 
  
   s:=mkslice() 
   println(s[0]) 
}

输出:

$go build-gcflags"-l"     // 禁用函数内联 
  
$go tool objdump-s"main\.mk"test
  
TEXT main.mkslice(SB)test.go
   CALL runtime.makeslice(SB) 
  
TEXT main.mkmap(SB)test.go
   CALL runtime.makemap(SB)

除new/make函数外,也可使用初始化表达式,编译器生成的指令基本相同。

当然,new函数也可为引用类型分配内存,但这是不完整创建。以字典(map)为例,它仅分配了字典类型本身(实际就是个指针包装)所需内存,并没有分配键值存储内存,也没有初始化散列桶等内部属性,因此它无法正常工作。

import"fmt" 
  
func main() { 
   p:=new(map[string]int)      // 函数new返回指针 
   m:= *p            
   m["a"] =1             //panic:assignment to entry in nil map(运行期错误) 
   fmt.Println(m) 
}